# -*- coding: utf-8 -*-
#
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

"""
发射器注册系统

提供统一的发射器注册和查找机制。
"""

from typing import List, Dict, Optional, Any
from ...ir import IRNode
from .emitter import BaseEmitter, EmitResult
from .context import CodeGenContext
from .emitter_index import EmitterIndexSystem, EmitterMatchResult


class EmitterRegistry:
    """发射器注册表

    管理所有代码发射器的注册和查找，使用索引系统提高性能。
    """

    def __init__(self):
        """初始化注册表"""
        self._index_system = EmitterIndexSystem()

    def register(self, emitter: BaseEmitter) -> None:
        """注册发射器

        Args:
            emitter: 要注册的发射器
        """
        self._index_system.add_emitter(emitter)

    def unregister(self, emitter: BaseEmitter) -> None:
        """注销发射器

        Args:
            emitter: 要注销的发射器
        """
        self._index_system.remove_emitter(emitter)

    def find_emitters(
        self, node: IRNode, context: CodeGenContext
    ) -> List[EmitterMatchResult]:
        """查找能处理指定节点的发射器

        Args:
            node: IR节点
            context: 代码生成上下文

        Returns:
            List[EmitterMatchResult]: 匹配的发射器结果列表，包含缓存数据
        """
        return self._index_system.find_emitters(node, context)

    def find_best_emitter(
        self, node: IRNode, context: CodeGenContext
    ) -> Optional[EmitterMatchResult]:
        """查找最佳的发射器

        Args:
            node: IR节点
            context: 代码生成上下文

        Returns:
            Optional[EmitterMatchResult]: 最佳发射器匹配结果，如果没有找到则返回None
        """
        return self._index_system.find_best_emitter(node, context)

    def get_all_emitters(self) -> List[BaseEmitter]:
        """获取所有注册的发射器

        Returns:
            List[BaseEmitter]: 所有发射器列表
        """
        return self._index_system.get_all_emitters()

    def clear(self) -> None:
        """清空所有注册的发射器"""
        self._index_system.clear()

    def emit_code(self, node: IRNode, context: CodeGenContext) -> EmitResult:
        """生成代码

        使用索引系统查找发射器，支持链式调度。
        优先检查节点的扩展发射器。

        Args:
            node: IR节点
            context: 代码生成上下文

        Returns:
            EmitResult: 生成结果
        """
        # 优先检查节点是否有扩展发射器
        emitter_callback = node.get_extension_param("emitter_callback")
        if emitter_callback:
            from .generator import get_global_generator

            generator = get_global_generator()
            code = emitter_callback(node, generator, context)
            return EmitResult(code=code, precedence=0, metadata={"success": True})

        # 查找匹配的发射器
        candidates = self.find_emitters(node, context)

        # 按优先级顺序尝试发射器
        for candidate in candidates:
            try:
                # 注入缓存数据到上下文
                self._inject_cached_data(context, candidate)

                # 尝试生成代码
                result = candidate.emitter.emit(node, context)

                # 如果返回 None，继续尝试其他发射器
                if result is None:
                    continue

                # 检查是否应该继续尝试其他发射器
                if self._should_continue(result):
                    continue
                else:
                    return result

            except Exception as e:
                # CodeGenError 及其子类应该立即传播，不应该被框架捕获
                from mcpy.codegen.errors import CodeGenError

                if isinstance(e, CodeGenError):
                    raise
                # 其他异常：发生时继续尝试下一个发射器
                continue

        # 如果所有发射器都失败，返回默认结果
        return EmitResult(
            code=f"/* No suitable emitter found for {type(node).__name__} */",
            precedence=0,
        )

    def get_performance_stats(self) -> Dict[str, Any]:
        """获取性能统计信息

        Returns:
            Dict[str, Any]: 统计信息
        """
        return {
            "total_emitters": len(self._index_system.get_all_emitters()),
        }

    def _inject_cached_data(
        self, context: CodeGenContext, candidate: EmitterMatchResult
    ) -> None:
        """将缓存数据注入到上下文中"""
        if not context.current_node:
            return

        emitter_name = candidate.emitter.get_name()
        for key, value in candidate.cached_data.items():
            cache_key = f"emitter:{id(context.current_node)}:{emitter_name}_{key}"
            # 发射器缓存数据使用节点级别缓存，避免污染
            context.cache_set_node(cache_key, value)

    def _should_continue(self, result: EmitResult) -> bool:
        """判断是否应该继续尝试其他发射器

        Args:
            result: 发射结果

        Returns:
            bool: 是否继续
        """
        # 如果结果为 None，继续尝试其他发射器
        if result is None:
            return True

        # 如果生成的代码是注释（表示失败），则继续
        if result.code.strip().startswith("/*") and result.code.strip().endswith("*/"):
            return True

        # 如果代码为空且没有明确的成功标记，则继续
        # 注意：某些语句（如 global、nonlocal）正确的行为就是生成空代码
        if not result.code.strip():
            # 检查是否有明确的成功标记
            if hasattr(result, "metadata") and result.metadata.get("success", False):
                return False  # 明确标记为成功，不继续
            # 默认情况下，空代码被视为失败，继续尝试
            return True

        # 检查是否有特殊的继续标记
        if hasattr(result, "metadata") and result.metadata.get("continue", False):
            return True

        # 默认情况下停止
        return False


_global_registry = EmitterRegistry()


def get_global_registry() -> EmitterRegistry:
    """获取全局发射器注册表

    Returns:
        EmitterRegistry: 全局注册表
    """
    return _global_registry


def register_emitter(emitter: BaseEmitter) -> None:
    """注册发射器到全局注册表

    Args:
        emitter: 要注册的发射器
    """
    _global_registry.register(emitter)
